home *** CD-ROM | disk | FTP | other *** search
- /*
- shutdown.c --- shutdown command.
-
- (c) Copyright 1995 SHW Wabnitz
- Written by Bernhard Fastenrath (fasten@shw.com)
-
- This file may be distributed under the terms
- of the GNU General Public License.
-
- History:
- 12-12-95, bf: fflush (stdout) added (for Syslog)
- 10-30-96, bf: shutdown delay
- 11-28-96, bf: message format changed
- 12-03-96, bf: gcc compatibility restored
- */
-
- #if defined (__SASC)
- #include <dos.h>
- #endif
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <intuition/intuition.h>
- #include <proto/exec.h>
- #include <proto/intuition.h>
-
- #include "queue/queue.h"
- #include "queue/shutdown.h"
- #include "shutdown_cmd.h"
- #include <shutdownbase.h>
-
- #if defined (__GNUC__)
- #include "queue/queue_inline.h"
- #elif defined (__SASC)
- #include "queue/queue_pragmas.h"
- #endif
-
- #if defined (__GNUC__)
- #include <shutdown_inline.h>
- #elif defined (__SASC)
- #include <shutdown_pragma.h>
- #endif
-
- #define SIGBREAKF_MASK ( SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | \
- SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F )
-
- int Unmount (char *filesystem, int mode);
-
- void GoDown (int time);
- void CleanUp (char *error);
- QMessage *BroadcastShutdownMsg (ULONG status, ULONG time);
-
- struct IntuitionBase *IntuitionBase = NULL;
- struct Library *QueueBase = NULL;
- struct Library *ShutdownBase = NULL;
- struct timerequest *TimerReq = NULL;
- struct MsgPort *TimerPort = NULL;
- struct MsgPort *ShutdownPort = NULL;
- QHandle ShutdownHandle = NULL;
- ULONG TimerMask;
- ULONG TimerErr = 1;
- ULONG ShutdownMask;
- ULONG WaitMask;
- ULONG QueueSignal, QueueMask;
- int point_of_no_return = 0;
- char *ShutdownPortname = "Shutdown";
- int SpNameLen;
- char *CantAllocatePort = "Can't allocate signal or message port.\n";
- char *ShutdownCancelled = "shutdown cancelled.\n";
- char *OutOfMemory = "Out of memory.\n";
- char *SorryTooLate = "Too late to stop shutdown.\n";
- int MessageTimedOut = 0;
- int HaltFlag = HFLG_HALT;
- int SyncTime = 5;
- int MaxTime = 60;
- int ShutdownTime = 10;
- int UseShutdownLibFlag = 0;
- int AbortableFlag = 1;
- int FastBoot = 0;
- int UnmountMode = UMNT_INHIBIT;
- int Error;
- char *optarg = NULL;
-
- int
- getopt (int argc, char *const *argv, const char *opts)
- {
- static int pos = 0;
- char *c;
-
- while (++pos < argc && argv[pos][0] != '-');
- if (pos >= argc)
- return -1;
- if ((c = strchr (opts, (int) argv[pos][1])) == 0)
- return (int) '?';
- if (*(c+1) != ':')
- return (int) *c;
- if (strlen (argv[pos]) > 2)
- optarg = argv[pos] + 2;
- else if (pos+1 < argc)
- optarg = argv[pos+1];
- else
- return (int) '?';
- return (int) *c;
- }
-
- ULONG
- PutAndGet (Message *msg, char *portname)
- {
- struct MsgPort *prt, *reply_port;
-
- if (!(reply_port = CreateMsgPort ()))
- return 1;
- msg -> mn_ReplyPort = reply_port;
-
- Forbid ();
- if (prt = FindPort (portname))
- {
- PutMsg (prt, msg);
- Permit ();
- do
- WaitPort (reply_port);
- while (!GetMsg (reply_port));
- }
- else
- Permit ();
-
- DeleteMsgPort (reply_port);
- return (ULONG) (prt ? 0 : 2);
- }
-
- void
- CancelRunningShutdown (void)
- {
- Message *msg;
-
- if (!(msg = AllocMem (sizeof (Message), MEMF_PUBLIC | MEMF_CLEAR)))
- CleanUp (OutOfMemory);
-
- switch (PutAndGet (msg, ShutdownPortname))
- {
- case 0:
- if (msg -> mn_Node.ln_Name == (APTR) -1)
- CleanUp (SorryTooLate);
- CleanUp (ShutdownCancelled);
- case 1:
- CleanUp (CantAllocatePort);
- case 2:
- CleanUp ("Shutdown is not running.\n");
- }
- FreeMem (msg, sizeof (Message));
- }
-
- void
- CleanUp (char *error)
- {
- QMessage *msg;
-
- if (error)
- printf (error);
- if (!TimerErr)
- CloseDevice ((struct IORequest *) TimerReq);
- if (TimerReq)
- DeleteIORequest (TimerReq);
- if (TimerPort)
- DeleteMsgPort (TimerPort);
- if (ShutdownPort)
- {
- if (ShutdownPort -> mp_Node.ln_Name)
- FreeMem (ShutdownPort -> mp_Node.ln_Name, SpNameLen);
- RemPort (ShutdownPort);
- DeleteMsgPort (ShutdownPort);
- }
- if (ShutdownHandle)
- {
- while (msg = QGetMsg (ShutdownHandle))
- QFreeMsg (msg, sizeof (ShutdownMessage));
- if (QClose (ShutdownHandle))
- {
- printf ("Exiting, waiting for replies.\n");
- while (QClose (ShutdownHandle) > 0)
- {
- Delay (50);
- while (msg = QGetMsg (ShutdownHandle))
- QFreeMsg (msg, sizeof (ShutdownMessage));
- }
- }
- FreeSignal (QueueSignal);
- }
- if (QueueBase)
- CloseLibrary (QueueBase);
- if (ShutdownBase)
- CloseLibrary (ShutdownBase);
- if (IntuitionBase)
- CloseLibrary ((struct Library *) IntuitionBase);
- exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
- }
-
- int
- CancelShutdown (void)
- {
- if (point_of_no_return)
- return 0;
-
- BroadcastShutdownMsg (SHUTDOWN_ABORT, 0);
- CleanUp (ShutdownCancelled);
- }
-
- QMessage *
- GetShutdownMessage (void)
- {
- QMessage *sm;
-
- for (;;)
- {
- if (sm = QGetMsg (ShutdownHandle))
- break;
- if (sm = QAllocMsg (sizeof (ShutdownMessage)))
- break;
- Delay (50);
- }
- return sm;
- }
-
- QMessage *
- BroadcastShutdownMsg (ULONG status, ULONG time)
- {
- ShutdownMessage *smsg;
- QMessage *qmsg;
-
- qmsg = GetShutdownMessage ();
- smsg = (ShutdownMessage *) qmsg -> qm_Data;
- smsg -> sm_Status = status;
- smsg -> sm_TimeLeft = time;
- QAddMsg (ShutdownHandle, qmsg);
- return qmsg;
- }
-
- void
- AbortableDelay (int seconds)
- {
- int abort = 0, sec;
- Message *msg;
- ULONG mask;
-
- TimerReq -> tr_node.io_Command = TR_ADDREQUEST;
- TimerReq -> tr_time.tv_secs = seconds;
- TimerReq -> tr_time.tv_micro = 0;
- SendIO ((struct IORequest *) TimerReq);
-
- while (1)
- {
- mask = Wait (WaitMask);
- if (mask & ShutdownMask)
- {
- if (msg = (Message *) GetMsg (ShutdownPort))
- {
- if (msg -> mn_Node.ln_Pri == 0) /* shutdown cancel request */
- {
- if (point_of_no_return || AbortableFlag == 0)
- msg -> mn_Node.ln_Name = (APTR) -1;
- else
- abort = 1;
- }
- else /* shutdown delay request */
- {
- sec = msg -> mn_Node.ln_Pri;
-
- if (MaxTime > 0)
- {
- if ((MaxTime -= sec) < 0)
- sec += MaxTime;
- ShutdownTime += sec;
- printf ("Shutdown delayed by %d seconds.\n", sec);
- msg -> mn_Node.ln_Pri = sec;
- }
- else
- {
- msg -> mn_Node.ln_Name = (APTR) -1;
- printf ("Shutdown delay refused.\n");
- }
- }
- ReplyMsg ((struct Message *) msg);
- }
- }
- if (mask & QueueMask)
- {
- /* Shutdown Queue reply: we aren't really interested
- because we take our messages fresh from the reply
- list when we need them.
- The timer is still running so we just wait some more.
- */
- }
- if (mask & SIGBREAKF_MASK || abort)
- {
- if (point_of_no_return)
- {
- printf (SorryTooLate);
- continue;
- }
- if (!(mask & TimerMask))
- AbortIO ((struct IORequest *) TimerReq);
- WaitIO ((struct IORequest *) TimerReq);
- SetSignal (0L, TimerMask);
-
- if (mask & SIGBREAKF_CTRL_C || abort)
- {
- if (mask & SIGBREAKF_CTRL_C)
- printf ("CTRL-C\n");
- CancelShutdown ();
- printf ("Timer stopped, press CTRL-E or CTRL-F to reboot.\n");
- }
- if (mask & SIGBREAKF_CTRL_D) /* CTRL-D: speed up */
- {
- printf ("CTRL-D\n");
- return;
- }
- if (!FastBoot)
- {
- FastBoot = 1;
- if (mask & SIGBREAKF_CTRL_E) /* CTRL-E: fast reboot */
- {
- printf ("CTRL-E\n");
- GoDown (5);
- }
- if (mask & SIGBREAKF_CTRL_F) /* CTRL-F: very fast reboot */
- {
- printf ("CTRL-F\n");
- GoDown (0);
- }
- }
- else
- return;
- }
- if (mask & TimerMask) /* done waiting */
- return;
- }
- }
-
- void
- GoingDownMessage (int seconds)
- {
- if (seconds / 3600)
- printf ("The system is going down in %d:%.2d hours.\n",
- seconds / 3600, (seconds % 3600) / 60);
- else if (seconds / 60)
- printf ("The system is going down in %d:%.2d minutes.\n",
- seconds / 60, seconds % 60);
- else
- printf ("The system is going down in %d seconds.\n", seconds);
- fflush (stdout);
- }
-
- int
- main (int argc, char *argv[])
- {
- int shutdown_interval;
- int cancel_flag = 0;
- int opt, rest;
-
- SetTaskPri (FindTask (0L), 10);
-
- /*** Options ***/
-
- while ((opt = getopt (argc, argv, "cehiM:nNrs:t:SW")) != -1)
- switch (opt)
- {
- case 'M': MaxTime = atoi (optarg); break;
- case 'W': UnmountMode = UMNT_READONLY; break;
- case 'S': UseShutdownLibFlag = 1; break;
- case 'R': UnmountMode = UMNT_REMOUNT; break;
- case 'n': AbortableFlag = 0; break;
- case 'r': HaltFlag = HFLG_REBOOT; break;
- case 'h': HaltFlag = HFLG_HALT; break;
- case 'e': HaltFlag = HFLG_EXIT; break;
- case 't': ShutdownTime = atoi (optarg); break;
- case 's': SyncTime = atoi (optarg); break;
- case 'c': cancel_flag = 1; break;
- case 'i': ShutdownTime = 0; MaxTime = 0; break;
- default:
- printf ("Usage: %s [-cehinNrSW] [-t <time>] [-M <max. time>] [-s <sync time>].\n", argv[0]);
- exit (EXIT_FAILURE);
- }
-
- /*** Libraries ***/
-
- if (HaltFlag)
- IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", 37);
- if (!(QueueBase = OpenLibrary ("queue.library", 3)))
- CleanUp ("Failed to open queue.library.\n");
- if (UseShutdownLibFlag)
- {
- if (!(ShutdownBase = OpenLibrary ("shutdown.library", 2)))
- CleanUp ("Failed to open shutdown.library.\n");
- }
-
- /*** Cancel shutdown ***/
-
- if (cancel_flag)
- CancelRunningShutdown ();
-
- /*** Remount ***/
-
- if (UnmountMode == UMNT_REMOUNT)
- {
- Unmount (NULL, UnmountMode);
- CleanUp ("Filesystems remounted.\n");
- }
-
- /*** Shutdown queue ***/
-
- if ((QueueSignal = AllocSignal (-1)) == -1)
- CleanUp (CantAllocatePort);
- QueueMask = 1 << QueueSignal;
- if (!(ShutdownHandle = QOpen ("shutdown", QMODE_SEND, QueueSignal)))
- {
- FreeSignal (QueueSignal);
- CleanUp ("Failed to open shutdown queue.\n");
- }
-
- /**** Timer device ***/
-
- if (!(TimerPort = CreateMsgPort ()))
- CleanUp (CantAllocatePort);
- if (!(TimerReq = (struct timerequest *)
- CreateIORequest (TimerPort, sizeof (struct timerequest))))
- CleanUp (OutOfMemory);
- if (TimerErr = OpenDevice (TIMERNAME, UNIT_VBLANK, (struct IORequest *) TimerReq, 0))
- CleanUp ("Can't open timer device.\n");
- TimerMask = 1 << TimerPort -> mp_SigBit;
-
- /*** Don't start shutdown twice ***/
-
- Forbid ();
- if (FindPort (ShutdownPortname))
- {
- Permit ();
- CleanUp ("Shutdown is already running.\n");
- }
- Permit ();
-
- /*** Named message port ***/
-
- if (!(ShutdownPort = CreateMsgPort ()))
- CleanUp (CantAllocatePort);
- if (!(ShutdownPort -> mp_Node.ln_Name =
- AllocMem (SpNameLen = strlen (ShutdownPortname) + 1, MEMF_PUBLIC)))
- CleanUp (OutOfMemory);
- bcopy (ShutdownPortname, ShutdownPort -> mp_Node.ln_Name, SpNameLen);
- ShutdownPort -> mp_Node.ln_Pri = 0;
- AddPort (ShutdownPort);
- ShutdownMask = 1 << ShutdownPort -> mp_SigBit;
-
- /*** Shutdown interval loop ***/
-
- WaitMask = QueueMask | ShutdownMask | TimerMask | SIGBREAKF_MASK;
-
- while (ShutdownTime >= 10)
- {
- GoingDownMessage (ShutdownTime);
- BroadcastShutdownMsg (SHUTDOWN_WARN, ShutdownTime);
- shutdown_interval = ShutdownTime / 3;
- ShutdownTime -= shutdown_interval;
- if (rest = ShutdownTime % 5)
- {
- shutdown_interval += rest;
- ShutdownTime -= rest;
- }
- AbortableDelay (shutdown_interval);
- }
- GoDown (ShutdownTime);
- }
-
- void
- GoDown (int time)
- {
- struct EasyStruct es = {
- sizeof (struct EasyStruct), 0, "AmigaDOS", "The system is halted", "Ok"
- };
- QMessage *smo, *smi;
- ULONG mask;
-
- if (UseShutdownLibFlag)
- {
- Shutdown (SHUTDOWN_EXTERN);
- }
-
- if (time)
- {
- /* last warning */
- GoingDownMessage (time);
- BroadcastShutdownMsg (SHUTDOWN_NOW, time);
- AbortableDelay (time);
-
- /* too late for writing */
- BroadcastShutdownMsg (SHUTDOWN_UMOUNT, 0);
- }
- point_of_no_return = 1;
-
- printf ("The system is going down, unmounting filesystems.\n");
- fflush (stdout);
- Unmount (NULL, UnmountMode);
- AbortableDelay (SyncTime);
-
- /*** all done, who turns off the light? ***/
- if (time && HaltFlag != HFLG_EXIT)
- {
- smo = BroadcastShutdownMsg (SHUTDOWN_HALT, 0);
-
- TimerReq -> tr_node.io_Command = TR_ADDREQUEST;
- TimerReq -> tr_time.tv_secs = 5;
- TimerReq -> tr_time.tv_micro = 0;
- SendIO ((struct IORequest *) TimerReq);
-
- for (;;) /*** Wait for the last broadcast to be replied ***/
- {
- mask = Wait (TimerMask | QueueMask);
- if (mask & QueueMask)
- while (smi = QGetMsg (ShutdownHandle))
- {
- if (smi == smo)
- mask |= TimerMask;
- QFreeMsg (smi, sizeof (ShutdownMessage));
- }
- if (mask & TimerMask)
- break;
- }
- }
- switch (HaltFlag)
- {
- case HFLG_HALT:
- printf ("The system is halted.\n");
- if (IntuitionBase)
- BuildEasyRequest (NULL, &es, NULL);
- Delay (10); /* wait 0.5 seconds */
- Disable ();
- while (1);
- case HFLG_REBOOT:
- ColdReboot ();
- case HFLG_EXIT:
- CleanUp ("Done.\n");
- }
- }
-